exec [system call]

fork() & exec() 시스템콜
fork() 시스템콜
    새로운 프로세스 공간을 별도로 만들고, fork() 시스템콜을 호출한 프로세스(부모 프로세스) 공간을 모두 복사
        별도의 프로세스 공간을 만들고, 부모 프로세스 공간의 데이터를 그대로 복사

exec() 시스템콜
    exec() 시스템콜을 호출한 현재 프로세스 공간의 TEXT, DATA, BSS 영역을 새로운 프로세스의 이미지로 덮어씌운다.
        별도의 프로세스 공간을 만들지 않는다.
exec() 시스템콜 family
#include <unistd.h>
int execl(const char* path, const char* arg, ...);
int execlp(const char* file, const char* arg, ...);
int execle(const char* path, const char* arg, ... , char* const envp[]);
int execv(const char* path, char* const argv[]);
int execvp(const char* file, char* const argv[]);
int execvpe(const char* file, char* const argv[], char* const envp[]);
l : argv가 list로 나열된다는 의미입니다. 그 것의 끝은 NULL
v : argv가 vector(배열)로 parameter를 하나를 받는다는 의미입니다. 배열의 마지막값은 NULL 
p : 첫번째 파라미터인 명령어/실행파일이 PATH로 지정된 디렉토리에 있다면 full path 또는 상대 path로 하지 않아도 된다는 뜻입니다.
 e : 설정할 환경변수를 parameter로 받는다는 의미입니다.
filename
    - 교체할 실행 파일 / 명령어.
    - filename은 실행가능한 binary이거나 shell이어야 합니다.
    - filename은 path가 설정되어 있는 디렉토리라고 하더라도 
      절대path나 상대path로 정확한 위치를 지정해야 합니다.
argv
    - c언어의 main(int argc, char *argv[])에서 argv와 비슷하며, main함수에는 argc가 있지만 
      execve에는 argc가 없으므로 main의 argv에 마지막 array 다음은 NULL이어야 있는 것과 같습니다.
envp
    - key=value형식의 환경변수 문자열 배열리스트로 마지막은 NULL이어야 합니다.
    - 만약 기 설정된 환경변수를 사용하려면 environ 전역변수를 그냥 사용합니다.
execl()
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void){
printf("execute ls \n");
execl("/bin/ls", "ls", "-l", NULL); //*arg0
// execl x
perror("execl is failed\n"); //stdlib.h:
exit(1); //stdlib.h:
}

celina@ubuntuserver:~/celina/test$ ./execl_test

execute ls 

total 152

-rwxrwxr-x 1 celina celina 16704 Jul 27 03:48 argv_test

-rw-rw-r-- 1 celina celina   206 Jul 27 03:48 argv_test.c

-rwx------ 1 celina celina   168 Jul 26 02:55 copy_test.txt

-rwxrwxr-x 1 celina celina 16832 Jul 27 03:54 execl_test

-rw-rw-r-- 1 celina celina   249 Jul 27 03:54 execl_test.c

-rwxrwxr-x 1 celina celina 16784 Jul 27 03:19 fork_test

-rw-rw-r-- 1 celina celina   322 Jul 27 03:19 fork_test.c

-rwxrwxr-x 1 celina celina 16792 Jul 27 02:58 getpid

-rw-rw-r-- 1 celina celina   144 Jul 27 02:50 getpid.c

drwxrwxr-x 2 celina celina  4096 Jul 26 03:47 link_test

-rw-rw-r-- 1 celina celina     0 Jul 26 03:27 link_test.txt

-rwxrwxr-x 1 celina celina 16464 Jul 23 03:50 loop

-rw-rw-r-- 1 celina celina    74 Jul 23 03:50 loop.c

-rw-rw-r-- 1 celina celina   159 Jul 23 03:54 loop.cpp

-rwxrwxr-x 1 celina celina 17992 Jul 23 03:55 loop2

lrwxrwxrwx 1 celina celina    13 Jul 26 03:26 softlink_test.txt -> link_test.txt

execl을 통해서 ls 명령어가 code에 덮어씌워지고 PC도 ls 시작점을 가르킴
execl(“디렉토리와 파일 이름이 합친 전체 이름”, “명령어 인수 리스트”, "끝은 NULL로 끝남”);
execlp(“파일 이름”, “명령어 인수 리스트”, “끝은 NULL로 끝남”);        //파일이름을 환경변수(path)에서 검색
명령어 인수 리스트
    argv[0]=“ls”
    argv[1]=“-al”
execl("/bin/ls", "ls", "-al", NULL);
execlp("ls", "ls", "-al", NULL);
execle(): 환경변수를 직접 지정함(envp)
char* envp[]={"USER=celina", "PATH=/bin", (char*)0};
execle("ls", "ls", "-al", NULL, envp);
execv(), execvp(), execve()
인자(명령어 인수)를 변수를 만들어서 대입
char* arg[]={"ls", "-al", NULL}
execv("/bin/ls", arg)
execvp("ls", arg);
char *envp[]={"USER=celina", "PATH=/bin", (char*)0};
execve("ls", arg, envp);
execve_test.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(void){
char *envp[]={"USER=celina", NULL};
char *arg[]={"ls", "-al", NULL};
printf("execute ls\n");
execve("/bin/ls", arg, envp);
perror("execl is failed");
exit(1);
}
python 실행 파일 exec로 실행하기
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h>
int main(void){
pid_t pid;
printf("Hello Now start Test!\n");
pid=fork();
if(pid==0){
printf("CHILD PROCESS. PID[%d]\n", getpid());
execlp("python", "python", "hello.py", "10", NULL);
perror("exec error!\n");
exit(1);
}
else if(pid>0){
printf("PARENT PROCESS. PID[%d]\n", getpid());
wait(NULL);
printf("ALL PROCESS FINISHED\n");
exit(0);
}
}